package net.esj.basic.dao.hibernate.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;

import net.esj.basic.dao.DaoSupport;
import net.esj.basic.dao.QueryBuilderDao;
import net.esj.basic.dao.hibernate.HibernateQueryBuilder;
import net.esj.basic.dao.hibernate.HibernateSessionLocale;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.utils.Pagination;
import net.esj.basic.utils.StringUtils;
import net.esj.basic.utils.Validators;
import net.esj.basic.utils.clone.ObjectWriteorRead;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;

public class HibernateQueryBuilderDaoImpl extends DaoSupport<HibernateSessionLocale> implements
		QueryBuilderDao {
	
	@Override
	public int queryCountByQueryBuilder(QueryBuilder qb) {
		Criteria criteria =  (Criteria) qb.invoke(getSession());
		//criteria.setProjection(Projections.count("id"));
		criteria.setProjection(Projections.rowCount());
		List counts = criteria.list();
		Iterator iterator = counts.iterator();
		int sum = 0;
		while (iterator.hasNext()) {
			sum = Integer.valueOf( iterator.next().toString());
		}
		return sum;
	}
	
	@Override
	public List queryListByQueryBuilder(QueryBuilder qb) {
		Criteria c = (Criteria) qb.invoke(getSession());
		List list= c.list();
		getSession().evict(list);
		return list;
	}

	@Override
	public Pagination queryPageByQueryBuilder(Pagination page) {
		
		//ClassMetadata c = getClassMetadata(page.getEntityClass());
		
//		ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
//		ObjectWriteorRead.writeObject(page.getQueryBuilder(), byteOut);// 序列化对象, 这里需要用到对象拷贝，一直没有好的办法，用克隆的方法没效果，所有暂时也不考虑效率了，这里希望大家提点建议
//		ByteArrayInputStream bytein = new ByteArrayInputStream(byteOut.toByteArray());
//		QueryBuilder newqb = (QueryBuilder) ObjectWriteorRead.readObject(bytein);
		QueryBuilder newqb = page.getQueryBuilder().clone4Count();
		
		Criteria pagec = (Criteria) newqb.invoke(getSession());
		Criteria criteria = (Criteria) page.getQueryBuilder().invoke(getSession());
		queryCount(pagec, page,page.getQueryBuilder().getDistinct());
		
		criteria.setMaxResults(page.getRp());
		criteria.setFirstResult((page.getPage() - 1) * page.getRp());
		List list = criteria.list();
		getSession().evict(list);
		page.setRows(list);
		return page;
	}

	@Override
	public List queryTopByQueryBuilder(QueryBuilder qb, int count) {
		Criteria c = (Criteria) qb.invoke(getSession());
		c.setMaxResults(count);
		List list =  c.list();
		getSession().evict(list);
		return list ;
	}

	protected void queryCount(Criteria criteria, Pagination page,String distinct) {
		//criteria.setProjection(Projections.count("id"));
		if(StringUtils.hasText(distinct)){
			criteria.setProjection(Projections.countDistinct(distinct));
		}else{
			criteria.setProjection(Projections.rowCount());
		}
		List counts = criteria.list();
		Iterator iterator = counts.iterator();
		int sum = 0;
		while (iterator.hasNext()) {
			sum = Integer.valueOf( iterator.next().toString());
		}
		//总数量
		page.setTotal(sum);
		//总页数
		page.setSum((sum-1)/page.getRp()+1);
	}
	
	protected final Session getSession(){
		return getSupportSource().getCurrentSession();
	}
	
	protected ClassMetadata getClassMetadata(Class clazz) {
        return (ClassMetadata) getSupportSource().getSessionFactory().getClassMetadata(clazz);
    }

	@Override
	public Object queryFirst(QueryBuilder qb) {
		List ts = queryTopByQueryBuilder(qb, 1);
		if(!Validators.isEmpty(ts)){
			Object o = ts.get(0);
			getSession().evict(o);
			return o;
		}else{
			return null;
		}
	}

	@Override
	public QueryBuilder getQueryBuilder(Class clazz) {
		return HibernateQueryBuilder.forClass(clazz);
	}

	@Override
	public Object queryMaxByQueryBuilder(QueryBuilder qb, String key) {
		Criteria c = (Criteria) qb.invoke(getSession());
		c.setProjection(Projections.projectionList().add(Projections.max(key)));
		Object o = c.uniqueResult();
		return o;
	}

	@Override
	public Long querySumByQueryBuilder(QueryBuilder qb, String key) {
		Criteria c = (Criteria) qb.invoke(getSession());
		c.setProjection(Projections.projectionList().add(Projections.sum(key)));
		Object o = c.uniqueResult();
		Long v = 0L;
		if(o instanceof Number){
			v = ((Number)o).longValue();
		}
		return v;
	}
	
 }
